/**
 * \file    rule.ccp
 * \brief   Parser generator.
 * \author  Jérôme LAURENS
 * \version 0.1
 * \date    September 17, 2014
 *
 * Reads a LALR(1) grammar, generates a parser based on a template file.
 * This is based on lemon parser generator, but has strongly been
 * revisited.
 *
 */

#include "rule.h"
#include "symbol.h"
#include <sstream>

LPP_NAMESPACE_BEGIN

bool operator<(RuleWRef const & __a, RuleWRef const & __b) {
    RuleRef a = __a.lock();
    RuleRef b = __b.lock();
    return (size_t)a.get()<(size_t)b.get();
}
bool operator<(RuleRef const & __a, RuleRef const & __b) {
    return compare(__a,__b)<0;
}

String Rule::short_description() const {
    std::ostringstream oss;
    oss<<lhs_symbol_m->name()<<" ::= ";
    String sep = "";
    for (SymbolRef const & __s: rhs_symbols_m) {
        oss<<sep;
        if (__s->is_multi_terminal()) {
            String separator = "";
            for (SymbolRef const & ___s: __s->get_sub_symbols()) {
                oss<<separator;
                separator = "|";
                oss<<___s->name();
            }
        } else {
            oss<<__s->name();
        }
        sep = " ";
    }
    return oss.str();
}

int compare(Rule const & __lhs, Rule const & __rhs) {
    if(__lhs.id()==0) {
        if(__rhs.id()==0) {
            return 0;
        } else {
            return -1;
        }
    } else if(__rhs.id()==0) {
        return 1;
    }
    if (!__lhs.lhs_symbol()) {
        std::cout<<"! Rule("<<__lhs.id()<<")"<<Description()(__lhs)<<std::endl;
    }
    if (!__rhs.lhs_symbol()) {
        std::cout<<"! Rule("<<__rhs.id()<<")"<<Description()(__rhs)<<std::endl;
    }
    int i = compare(__lhs.lhs_symbol(),__rhs.lhs_symbol());
    if (i) return i;
    i = compare(__lhs.rhs_symbols(),__rhs.rhs_symbols());
    if (i) return i;
    if(__lhs.index()<__rhs.index()) return -1;
    if(__lhs.index()>__rhs.index()) return  1;
    if(__lhs.id()<__rhs.id()) return -1;
    if(__lhs.id()>__rhs.id()) return  1;
    return 0;
}
int compare(RuleRef const & __lhs, RuleRef const & __rhs) {
    return compare_Ref<RuleRef>(__lhs,__rhs);
}
int compare(RuleWRef const & __lhs, RuleWRef const & __rhs) {
    return compare_WRef<RuleWRef>(__lhs,__rhs);
}

LPP_NAMESPACE_END

size_t std::hash<LPP_NAMESPACE_NAME::RuleRef>::operator()(LPP_NAMESPACE_NAME::RuleRef const & x) const {
    return reinterpret_cast<std::uintptr_t>(x.get());
}

